
#include <algorithm>
#include "area.h"
#include "avatar.h"
#include "commandTable.h"
#include "commandTable-default.h"
#include "display.h"
#include "handler.h"
#include "room.h"
#include "symphony.h"
#include "world.h"

/*
Cmd::Cmd( void ) {
  name( "" );
  return;
}

bool Cmd::execute( Creature* creature, const std::string& args ) {

  return true;
}
*/

CmdAsave::CmdAsave( void ) {
  name( "asave" );
  level( BUILDER );
  return;
}

bool CmdAsave::execute( Creature* creature, const std::string& args ) {
  World::Instance().save();
  creature->send( "Areas saved successfully." );
  return true;
}

CmdAt::CmdAt( void ) {
  name( "at" );
  level( BUILDER );
  syntax( "syntax: at <vnum> <command> [arguments]\n        at <player> <command> [arguments]\n        at <mob> <command> [arguments]" );
  return;
}

bool CmdAt::execute( Creature* creature, const std::string& args ) {
  std::vector<std::string> pieces = Regex::split( args, 1 );
  Creature* foo = NULL;
  Room* current = creature->room();
  Room* target = NULL;

  if ( pieces.size() != 2 ) {
    creature->send( syntax() );
    return false;
  }

  if ( Regex::match( "^[0-9]+$", pieces[0] ) ) {
    if ( ( target = World::Instance().findRoom( estring(pieces[0]) ) ) == NULL ) {
      creature->send( "That room doesn't exist." );
      return false;
    }
  } else {
    if ( ( foo = World::Instance().findCreature( estring(pieces[0]) ) ) == NULL ) {
      creature->send( "They aren't around at the moment." );
      return false;
    }
    target = foo->room();
  }

  creature->room( target );
  creature->handler()->handle( pieces[1] );
  creature->room( current );

  return true;
}

CmdAedit::CmdAedit( void ) {
  name( "aedit" );
  level( BUILDER );
  syntax( "syntax: aedit <areaID>\n        aedit create <first_vnum> <size>" );
  return;
}

bool CmdAedit::execute( Creature* creature, const std::string& args ) {
  std::set<Area*,area_comp>::iterator it;
  std::vector<std::string> pieces = Regex::split( args, 3 );
  Area* area = NULL;
  unsigned short minimum = 25;
  unsigned short multiple = 5;

  if ( pieces.size() == 3 && pieces[0] == "create" ) {
    unsigned long low = estring(pieces[1]);
    unsigned long size = estring(pieces[2]);
    unsigned long high = low + size - 1;
    // Check permissions...
    if ( !creature->admin( ADMIN_HEAD_BUILDER ) && creature->level() < CREATOR ) {
      creature->send( "Only the Head Builder can create new areas." );
      return false;
    }
    // Check to make sure vnums are good...
    if ( low % minimum ) {
      creature->send( "The first vnum of an area must be a multiple of %lu.", multiple );
      return false;
    }
    if ( size < 25 || size % minimum ) {
      creature->send( "Area sizes must be a multiple of %lu, and at least %lu.", multiple, minimum );
      return false;
    }
    for ( it = World::Instance().getAreas().begin(); it != World::Instance().getAreas().end(); ++it ) {
      if ( ( (*it)->low() < low && low < (*it)->high() ) || ( (*it)->low() < high && high < (*it)->high() ) ) {
        creature->send( "That would cause a vnum collision with %s (area %lu).  Please check your numbers.", (*it)->name().c_str(), (*it)->ID() );
        return false;
      }
    }
    area = new Area( low, high );
    if ( !area->ID() ) {
      creature->send( "Something went wrong while creating the area." );
      World::Instance().worldLog( ERROR, LOG_WORLD, "%lu failed to create area from %lu through %lu.", creature->ID(), area->low(), area->high() );
      delete area;
      return false;
    }
    creature->mode( MODE_AEDIT );
    creature->aedit( area );
    World::Instance().insert( area );
    ((Avatar*)creature)->pushHandler( new AeditHandler( (Avatar*)creature ) );
    creature->send( "You've created a new area (number %lu) with vnums %lu through %lu.", area->ID(), area->low(), area->high() );
  } else if ( pieces.size() == 1 ) {
    // Check for the area...
    if ( ( area = World::Instance().findArea( estring(pieces[0]) ) ) == NULL ) {
      creature->send( "That area doesn't exist." );
      return false;
    }
    // Check permissions...
    if ( ( area->ID() == 1 && creature->level() < CREATOR ) || !World::Instance().hasPermission( area, (Avatar*)creature ) ) {
      creature->send( "You can't edit %s.", area->name().c_str() );
      return false;
    }
    // Make sure no one else is editing the area...
    for ( std::map<std::string,Avatar*>::iterator it = World::Instance().getAvatars().begin(); it != World::Instance().getAvatars().end(); ++it ) {
      if ( it->second->mode() == MODE_AEDIT && it->second->aedit() == area ) {
        creature->send( "Sorry, %s is currently editing %s (area %lu).", creature->seeName( ((Creature*)it->second) ).c_str(), area->name().c_str(), area->ID() );
        return false;
      }
    }
    // Send them on to the editor...
    creature->send( "You're editing %s (%lu).", area->name().c_str(), area->ID() );
    creature->mode( MODE_AEDIT );
    creature->aedit( area );
    ((Avatar*)creature)->pushHandler( new AeditHandler( (Avatar*)creature ) );
  } else {
    creature->send( syntax() );
    return false;
  }

  return true;
}

CmdAreas::CmdAreas( void ) {
  name( "areas" );
  return;
}

bool CmdAreas::execute( Creature* creature, const std::string& args ) {
  std::string output( "Areas:" );
  char buffer[MAX_BUFFER];

  for ( std::set<Area*,area_comp>::iterator it = World::Instance().getAreas().begin(); it != World::Instance().getAreas().end(); ++it ) {
    if ( creature->level() >= BUILDER ) {
      if ( World::Instance().hasPermission( *it, (Avatar*)creature ) ) {
        sprintf( buffer, "\n ({Y%3lu{x) [ {C%4lu{x - {C%4lu{x ] {M%s{x", (*it)->ID(), (*it)->low(), (*it)->high(), (*it)->name().c_str() );
      } else {
        sprintf( buffer, "\n ({y%3lu{x) [ {c%4lu{x - {c%4lu{x ] {m%s{x", (*it)->ID(), (*it)->low(), (*it)->high(), (*it)->name().c_str() );
      }
    } else {
      sprintf( buffer, "\n %s", (*it)->name().c_str() );
    }
    output.append( buffer );
  }

  creature->send( output );
  return true;
}

CmdBigBrother::CmdBigBrother( void ) {
  name( "bigbrother" );
  level( GOD );
  return;
}

bool CmdBigBrother::execute( Creature* creature, const std::string& args ) {
  std::vector<std::string> pieces = Regex::split( args, 2 );
  std::string output;
  std::string on = "[{GON{x]";
  std::string off = "[{rOFF{x]";
  bool toggle = false;
  bool status = true;

  // No arguments...
  if ( !pieces.size() ) {
    output.append( "\nBigBrother:                   " ).append( creature->admin( ADMIN_BIGBRO ) ? on : off ).append( "\n" );
    output.append( "\n -Logins/Logouts  (\"logins\")  " ).append( creature->admin( ADMIN_BIGBRO_LOGINS ) ? on : off );
    output.append( "\n -Edit modes      (\"modes\")   " ).append( creature->admin( ADMIN_BIGBRO_MODES ) ? on : off );
    output.append( "\n -Player deaths   (\"deaths\")  " ).append( creature->admin( ADMIN_BIGBRO_DEATHS ) ? on : off );
    output.append( "\n -World Schedule  (\"events\")  " ).append( creature->admin( ADMIN_BIGBRO_EVENTS ) ? on : off );
    output.append( "\n -System Events   (\"system\")  " ).append( creature->admin( ADMIN_BIGBRO_SYSTEM ) ? on : off );
    output.append( "\n -World Changes   (\"changes\") " ).append( creature->admin( ADMIN_BIGBRO_CHANGES ) ? on : off );
  } else if ( pieces.size() == 1 ) {
    output.append( "BigBrother is now " );
    if ( pieces[0] == "on" ) {
      creature->admin( ADMIN_BIGBRO, true );
      output.append( on );
    } else {
      creature->admin( ADMIN_BIGBRO, false );
      output.append( off );
    }
  } else if ( pieces.size() == 2 ) {
    toggle = pieces[1] == "on" ? true : false;
    if ( toggle ) {
      creature->admin( ADMIN_BIGBRO, true );
    }
    if ( pieces[0] == "logins" ) {
      creature->admin( ADMIN_BIGBRO_LOGINS, toggle );
      output.append( "BigBrother login module is now " ).append( toggle ? on : off );
    } else if ( pieces[0] == "modes" ) {
      creature->admin( ADMIN_BIGBRO_MODES, toggle );
      output.append( "BigBrother modes module is now " ).append( toggle ? on : off );
    } else if ( pieces[0] == "deaths" ) {
      creature->admin( ADMIN_BIGBRO_DEATHS, toggle );
      output.append( "BigBrother deaths module is now " ).append( toggle ? on : off );
    } else if ( pieces[0] == "events" ) {
      creature->admin( ADMIN_BIGBRO_EVENTS, toggle );
      output.append( "BigBrother events module is now " ).append( toggle ? on : off );
    } else if ( pieces[0] == "system" ) {
      creature->admin( ADMIN_BIGBRO_SYSTEM, toggle );
      output.append( "BigBrother system module is now " ).append( toggle ? on : off );
    } else if ( pieces[0] == "changes" ) {
      creature->admin( ADMIN_BIGBRO_CHANGES, toggle );
      output.append( "BigBrother changes module is now " ).append( toggle ? on : off );
    } else if ( pieces[0] == "all" ) {
      creature->admin( ADMIN_BIGBRO_LOGINS | ADMIN_BIGBRO_MODES | ADMIN_BIGBRO_DEATHS | ADMIN_BIGBRO_EVENTS, toggle );
      output.append( "All BigBrother subsystems are now " ).append( toggle ? on : off );
    } else {
      output.append( "Module name not recognized" );
      status = false;
    }
  } else {
    output.append( "Too many arguments." );
    status = false;
  }

  creature->send( output );
  return status;
}

CmdChannels::CmdChannels( void ) {
  name( "channels" );
  return;
}

bool CmdChannels::execute( Creature* creature, const std::string& args ) {
  std::string output;
  std::string on = "{x[{GON{x]";
  std::string off = "{x[{rOFF{x]";

  output.append( "\nCurrent channels:" );
  output.append( "\n -Tell/Reply:     " ).append( creature->channel( CHAN_TELL ) ? on : off );
  output.append( "\n -OOC:            " ).append( creature->channel( CHAN_OOC ) ? on : off );

  creature->send( output );
  return true;
}

CmdCommands::CmdCommands( void ) {
  name( "commands" );
  return;
}

CmdClose::CmdClose( void ) {
  name( "close" );
  syntax( "syntax: close <direction>" );
  return;
}

bool CmdClose::execute( Creature* creature, const std::string& args ) {
  Exit* exit = NULL;
  Exit* inv = NULL;

  if ( ( exit = creature->room()->exit( args ) ) == NULL ) {
    creature->send( "There is no door in that direction." );
    return false;
  }

  if ( exit->flag( EFLAG_CLOSED ) ) {
    creature->send( "It's already closed." );
    return false;
  }

  if ( !exit->flag( EFLAG_CLOSEABLE ) ) {
    creature->send( "You can't close that." );
    return false;
  }

  exit->flag( EFLAG_CLOSED, true );
  creature->send( "You close the door." );
  creature->room()->send( "$p closed the way $e.", creature, exit );
  if ( ( inv = exit->target()->exit( Exit::inverse( exit->direction() ) ) ) != NULL ) {
    exit->target()->send( "The way $e has been closed.", NULL, inv );
  }

  return true;
}

bool CmdCommands::execute( Creature* creature, const std::string& args ) {
  CommandTable* table = ((Avatar*)creature)->handler()->commandTable();
  std::map<unsigned short,std::vector<std::string> > commands;
  std::vector<std::string> special_commands;
  std::string output;

  // Find and display all 'special' commands (if we've got any)...
  for ( std::vector<Command*>::iterator it = table->commands().begin(); it != table->commands().end(); ++it ) {
    if ( creature->level() >= (*it)->level() && (*it)->special() ) {
      special_commands.push_back( (*it)->name() );
    }
  }
  if ( !special_commands.empty() ) {
    sort( special_commands.begin(), special_commands.end() );
    output.append( "\n--== {c" ).append( table->name() ).append( " Commands {x==--\n" ).append( Display::formatColumns( 5, special_commands ) );
  }

  // Find and display all 'standard' commands...
  for ( std::vector<Command*>::iterator it = table->commands().begin(); it != table->commands().end(); ++it ) {
    if ( creature->level() >= (*it)->level() && !(*it)->special() ) {
      commands[(*it)->level()].push_back( (*it)->name() );
    }
  }
  for ( std::map<unsigned short,std::vector<std::string> >::reverse_iterator m_it = commands.rbegin(); m_it != commands.rend(); ++m_it ) {
    sort( m_it->second.begin(), m_it->second.end() );
    switch ( m_it->first ) {
      case CREATOR: output.append( "\n--== {cAdministrator" ); break;
      case GOD: output.append( "\n--== {cGod" ); break;
      case DEMIGOD: output.append( "\n--== {cDemigod" ); break;
      case BUILDER: output.append( "\n--== {cBuilder" ); break;
      case IMMORTAL: output.append( "\n--== {cImmortal" ); break;
      case KING: output.append( "\n--== {cKing" ); break;
      case DUKE: output.append( "\n--== {cDuke" ); break;
      case LORD: output.append( "\n--== {cLord" ); break;
      case HERO: output.append( "\n--== {cHero" ); break;
      default: output.append( "\n--== {cGeneral" ); break;
    }
    output.append( " Commands {x==--\n" ).append( Display::formatColumns( 5, m_it->second ) );
  }

  creature->send( output );
  return true;
}

CmdColors::CmdColors( void ) {
  name( "colors" );
  return;
}

bool CmdColors::execute( Creature* creature, const std::string& args ) {
  std::string output;

  output.append( "Supported color codes:\n\n" );
  output.append( "  {{r {rdark red      {x{{R {Rbright red{x\n" );
  output.append( "  {{g {gdark green    {x{{G {Gbright green{x\n" );
  output.append( "  {{y {ydark yellow   {x{{Y {Ybright yellow{x\n" );
  output.append( "  {{b {bdark blue     {x{{B {Bbright blue{x\n" );
  output.append( "  {{m {mdark magenta  {x{{M {Mbright magenta{x\n" );
  output.append( "  {{c {cdark cyan     {x{{C {Cbright cyan{x\n" );
  output.append( "  {{w {wdark gray     {x{{W {Wpure white{x\n" );

  creature->send( output );
  return true;
}

CmdDrop::CmdDrop( void ) {
  name( "drop" );
  syntax( "syntax: drop <object>\n        drop all" );
  return;
}

bool CmdDrop::execute( Creature* creature, const std::string& args ) {
  Object* object = NULL;

  if ( args == "all" ) {
    creature->room()->objects().splice( creature->room()->objects().begin(), creature->objects() );
    creature->send( "You drop everything in your inventory." );
    creature->room()->send( "$p drops some things.", creature );
    return true;
  }

  if ( ( object = creature->findObject( args, SEARCH_CARRY ) ) == NULL ) {
    creature->send( "You aren't carrying that." );
    return false;
  }

  creature->remove( object );
  creature->room()->add( object );
  creature->send( "You drop %s.", object->shortname().c_str() );
  creature->room()->send( "$p drops $o.", creature, object );

  return true;
}

CmdEat::CmdEat( void ) {
  name( "eat" );
  level( BUILDER );
  syntax( "syntax: eat <object>" );
  return;
}

bool CmdEat::execute( Creature* creature, const std::string& args ) {
  Object* target = NULL;

  if ( ( target = creature->findObject( args ) ) == NULL ) {
    creature->send( "You aren't carrying that." );
    return false;
  }

  creature->remove( target );
  creature->send( "You eat %s", target->shortname().c_str() );
  creature->room()->send_cond( "$p eats $o.", creature, target );
  delete target;

  return true;
}

CmdEmote::CmdEmote( void ) {
  name( "emote" );
  return;
}

bool CmdEmote::execute( Creature* creature, const std::string& args ) {
  std::string text = Regex::trim(args);

  if ( text.empty() ) {
    creature->send( "Emote what?" );
    return false;
  }

  creature->room()->send( "$p $s", creature, (void*)text.c_str(), NULL, TO_ALL );

  return true;
}

CmdExit::CmdExit( void ) {
  name( "exit" );
  level( BUILDER );
  return;
}

bool CmdExit::execute( Creature* creature, const std::string& args ) {

  creature->mode( MODE_NONE );
  ((Avatar*)creature)->popHandler();

  return true;
}

CmdForce::CmdForce( void ) {
  name( "force" );
  level( BUILDER ); 
  syntax( "syntax: force <player> <command> [arguments]\n        force <mob> <command> [arguments]" );
  return;
}

bool CmdForce::execute( Creature* creature, const std::string& args ) {
  std::vector<std::string> pieces = Regex::split( args, 1 );
  Creature* target = NULL;

  if ( pieces.size() != 2 ) {
    creature->send( syntax() );
    return false;
  }

  // Aquire target...
  if ( ( target = World::Instance().findCreature( pieces[0] ) ) == NULL ) {
    creature->send( "They're not around at the moment." );
    return false;
  }

  // Check permissions...
  if ( !creature->canAlter( target ) ) {
    creature->send( "You can't tell %s what to do!", target->name().c_str() );
    target->send( "%s tried to make you \"%s\"", creature->name().c_str(), pieces[1].c_str() );
    return false;
  }

  // Force the command...
  target->send( "%s forces you into action.\n", target->seeName( creature, true ).c_str() );
  creature->send( "%s does as you command.\n", target->name().c_str() );
  if ( !target->handlers().empty() ) {
    // Mobs don't have input handlers, so without this check, forcing a mob into any action would seg fault
    target->handler()->handle( pieces[1] );
  }

  return true;
}

